package main

import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strconv"
	"sync"
	"time"

	"github.com/hashicorp/memberlist"
)

var name = "nil"
var randID uint64

type myDelegate struct{}

func (d *myDelegate) NotifyMsg(msg []byte) {
	fmt.Println("Received message:", string(msg))
}

// GetBroadcasts 返回需要广播的消息（若无返回 nil）
func (d *myDelegate) GetBroadcasts(overhead, limit int) [][]byte {
	return nil // 示例中暂不广播消息
}

// NodeMeta 返回节点的元数据（如自定义标签）
func (d *myDelegate) NodeMeta(limit int) []byte {
	return []byte("custom-metadata")
}

// 节点状态
type NodeState struct {
	NodeID uint64  // 存储时候的索引
	Name   string  // 节点名称
	Load   float64 // 节点负载
	Mem    int64   // 节点内存
}

// LocalState 返回本地状态（用于同步）
func (d *myDelegate) LocalState(join bool) []byte {
	// 可以改成动态获取
	state := NodeState{NodeID: randID, Name: name, Load: 0.5, Mem: 2048}
	data, _ := json.Marshal(state)
	return data // 序列化为字节流
}

// 存储其他节点的状态
var peerStates sync.Map // 线程安全的 Map
// var globalIDs []uint64 // 全局ID列表

func (d *myDelegate) MergeRemoteState(buf []byte, join bool) {
	var remoteState NodeState
	if err := json.Unmarshal(buf, &remoteState); err != nil {
		return
	}

	// 存储或更新对端节点状态
	peerStates.Store(remoteState.NodeID, remoteState)

	fmt.Printf("Updated state from %s: CPU=%.1f%%, Mem=%d%%\n",
		remoteState.Name, remoteState.Load, remoteState.Mem)
}

// 节点状态查询
// func get_remotestate(id uint64) NodeState {
// 	if val, ok := peerStates.Load(id); ok {
// 		return val.(NodeState)
// 	}
// 	return NodeState{}
// }

func main() {
	// 1. 读取命令行参数（节点名称和端口）
	name = os.Args[1]
	port, err := strconv.Atoi(os.Args[2])
	if err != nil {
		log.Fatal("Failed to parse port: ", err)
	}
	seed := os.Args[3] // 种子节点地址（格式：IP:PORT）

	// 随机生成节点 ID
	// rand.Seed(time.Now().UnixNano())
	randID = rand.Uint64()

	// 2. 配置 Memberlist
	config := memberlist.DefaultLocalConfig()
	config.Name = name          // 节点唯一标识
	config.BindPort = port      // Gossip 协议默认端口
	config.AdvertisePort = port // 对外广播的端口
	// 接收消息
	config.Delegate = &myDelegate{}

	// 3. 创建 Memberlist 实例
	list, err := memberlist.Create(config)
	if err != nil {
		log.Fatal("Failed to create memberlist: ", err)
	}

	// 4. 加入集群（通过种子节点）
	if seed != "" {
		_, err = list.Join([]string{seed})
		if err != nil {
			log.Fatal("Failed to join cluster: ", err)
		}
	}

	// 5. 打印集群成员列表
	go printMembers(list)

	go query_node_state(list, port)

	// go func() {
	// 	// 发送消息
	// 	for {
	// 		time.Sleep(3 * time.Second)
	// 		members := list.Members()
	// 		msg := []byte("Hello from " + name + "!")
	// 		// 如果整个集群只有一个节点，则不发送消息
	// 		len_of_group := len(members)
	// 		if len_of_group == 1 {
	// 			continue
	// 		}
	// 		// 随机选择一个节点发送消息
	// 		id := rand.Intn(len_of_group)
	// 		// 避免发送给自己
	// 		for members[id].Port == uint16(port) {
	// 			id = rand.Intn(len_of_group)
	// 		}
	// 		// 发送消息
	// 		list.SendReliable(members[id], msg) // 发送给指定节点
	// 	}
	// }()

	// 6. 保持运行（模拟节点持续工作）
	select {}
}

// 定期打印集群成员状态
func printMembers(list *memberlist.Memberlist) {
	for {
		time.Sleep(2 * time.Second)
		members := list.Members()
		fmt.Println("Current cluster members:")
		for _, member := range members {
			fmt.Printf("  - %s (%s:%d)\n", member.Name, member.Addr, member.Port)
		}
	}
}

// 查询所有节点状态
func query_node_state(list *memberlist.Memberlist, localPort int) {
	for {
		time.Sleep(3 * time.Second)
		members := list.Members()
		if len(members) == 1 {
			continue
		}
		id := rand.Intn(len(members))
		for members[id].Port == uint16(localPort) {
			id = rand.Intn(len(members))
		}
		peerStates.Range(func(k, v interface{}) bool {
			fmt.Printf("QUERY: Id = %d, %v\n", k, v)
			return true
		})
	}
}
